package com.grass.cropTradingCenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.grass.cropTradingCenter.common.OutputException;
import com.grass.cropTradingCenter.domain.repository.CropRepository;
import com.grass.cropTradingCenter.domain.repository.UserStarRepository;
import com.grass.cropTradingCenter.mapper.MiniUserMapper;
import com.grass.cropTradingCenter.mapper.ShippingAddressMapper;
import com.grass.cropTradingCenter.pojo.entity.MiniShop;
import com.grass.cropTradingCenter.pojo.entity.MiniUser;
import com.grass.cropTradingCenter.pojo.entity.ShippingAddress;
import com.grass.cropTradingCenter.pojo.entity.UserStar;
import com.grass.cropTradingCenter.pojo.po.StarType;
import com.grass.cropTradingCenter.pojo.vo.user.FollowOrUnFollowShop;
import com.grass.cropTradingCenter.pojo.vo.user.LoginVo;
import com.grass.cropTradingCenter.pojo.vo.user.RegisterVo;
import com.grass.cropTradingCenter.pojo.vo.user.SendUserLoginVo;
import com.grass.cropTradingCenter.service.EmailService;
import com.grass.cropTradingCenter.service.MiniShopService;
import com.grass.cropTradingCenter.service.MiniUserService;
import com.grass.cropTradingCenter.utils.SafeUtils;
import com.grass.cropTradingCenter.utils.SecurityUtils;
import com.grass.cropTradingCenter.utils.TokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author zipan
* @description 针对表【mini_user】的数据库操作Service实现
* @createDate 2024-01-23 19:41:54
*/
@Service
public class MiniUserServiceImpl extends ServiceImpl<MiniUserMapper, MiniUser>
    implements MiniUserService{

    @Autowired
    EmailService emailService;

    @Autowired
    RedissonClient redissonClient;


    @Autowired
    ShippingAddressMapper shippingAddressMapper;

    @Autowired
    UserStarRepository userStarRepository;

    @Autowired
    MiniShopService shopService;

    @Autowired
    CropRepository cropRepository;

    /**
     * 登录邮箱注册
     *
     * @param vo
     */
    @Override
    public void sendEmailLogin(SendUserLoginVo vo) {
        // 查看是否有该用户
        LambdaQueryWrapper<MiniUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MiniUser::getUserEmail, vo.getEmail());
        int count = this.count(wrapper);
        if(count <= 0){
            throw new OutputException("请先注册");
        }

        emailService.sendCode(vo.getEmail());
    }

    @Override
    public void sendEmailRegister(SendUserLoginVo vo) {
        // 查看是否有该用户
        LambdaQueryWrapper<MiniUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MiniUser::getUserEmail, vo.getEmail());
        int count = this.count(wrapper);
        if(count > 0){
            throw new OutputException("该账号已经存在");
        }

        emailService.sendCode(vo.getEmail());
    }

    @Override
    public String login(LoginVo vo) {
        MiniUser miniUser = null;
        // 验证码登录
        if(!StringUtils.isBlank(vo.getIdCode())){
            emailService.checkIdCode(vo.getEmail(), vo.getIdCode());
        } else{ // 账号密码登录
            LambdaQueryWrapper<MiniUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MiniUser::getUserEmail, vo.getEmail())
                    .eq(MiniUser::getUserPassword, SafeUtils.getSafePassword(vo.getPassword()));
            int count = this.count(wrapper);
            if(count <= 0) throw new OutputException("账号密码错误");
        }

        // 查找用户
        LambdaQueryWrapper<MiniUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MiniUser::getUserEmail, vo.getEmail());
        miniUser = this.getOne(wrapper);
        miniUser.setLastLoginTime(miniUser.getThisLoginTime());
        miniUser.setThisLoginTime(new Date());
        this.updateById(miniUser);
        return TokenUtil.getToken(miniUser.getUserId(), "user");
    }

    /**
     * 注册，返回token
     * @param vo
     * @return
     */
    @Override
    public String register(RegisterVo vo) {
        // 密码不为空
        if(StringUtils.isBlank(vo.getPassword())) throw new OutputException("密码不能为空");
        if(!vo.getPassword().equals(vo.getCheckPassword())) throw new OutputException("两次密码不一致");
        String safePassword = SafeUtils.getSafePassword(vo.getPassword());

        emailService.checkIdCode(vo.getEmail(), vo.getIdCode());
        MiniUser miniUser = null;
        RLock lock = redissonClient.getLock("REGISTER#" + vo.getEmail());
        boolean isLock = false;
        try {
            isLock = lock.tryLock(3,3, TimeUnit.SECONDS);
            if(isLock){
                // 添加用户信息
                miniUser = new MiniUser();
                miniUser.setUserEmail(vo.getEmail());
                miniUser.setNickName(vo.getNickName());
                miniUser.setUserAvatar("https://grassmall.oss-cn-beijing.aliyuncs.com/3ea6beec64369c2642b92c6726f1e.png");

                miniUser.setUserPassword(safePassword);
                this.save(miniUser);
            }else{
                throw new OutputException("网络繁忙，请重试");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if(lock.isLocked()) lock.unlock();
        }
        if(miniUser != null)
            return TokenUtil.getToken(miniUser.getUserId(), "user");
        else throw new OutputException("网络繁忙，请重试");
    }

    @Override
    public String findPassword(RegisterVo vo) throws InterruptedException {
        // 密码不为空
        if (StringUtils.isBlank(vo.getPassword())) throw new OutputException("密码不能为空");
        if (!vo.getPassword().equals(vo.getCheckPassword())) throw new OutputException("两次密码不一致");
        String safePassword = SafeUtils.getSafePassword(vo.getPassword());

        emailService.checkIdCode(vo.getEmail(), vo.getIdCode());
        MiniUser miniUser = null;
        RLock lock = redissonClient.getLock("REGISTER#SHOP#" + vo.getEmail());
        boolean isLock = false;
        try {
            isLock = lock.tryLock(3, 3, TimeUnit.SECONDS);
            if (isLock) {
                LambdaQueryWrapper<MiniUser> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MiniUser::getUserEmail, vo.getEmail());
                miniUser = this.getOne(queryWrapper);
                if (miniUser == null) throw new OutputException("账户不存在");
                miniUser.setUserPassword(safePassword);
                this.updateById(miniUser);
            } else {
                throw new OutputException("网络繁忙，请重试");
            }
        } finally {
            if (lock.isLocked()) lock.unlock();
        }
        if (miniUser != null)
            return TokenUtil.getToken(miniUser.getUserId(), "user");
        else throw new OutputException("网络繁忙，请重试");
    }

    @Override
    public MiniUser getUserInfo() {
        int userId = SecurityUtils.getUserId();
        MiniUser user = this.getById(userId);
        // 关注商品数量
        user.setCollectGoodsNum(userStarRepository.getStarNum(1));
        // 关注店铺
        user.setFollowShopNum(userStarRepository.getStarNum(2));
        return user;
    }

    @Override
    public void modify(MiniUser user) {
        int userId = SecurityUtils.getUserId();
        if(userId != user.getUserId()){
            throw new OutputException("操作有误");
        }
        this.updateById(user);
    }

    @Override
    public void addOrUpdateAddress(ShippingAddress vo) {
        int userId = SecurityUtils.getUserId();
        vo.setUserId(userId);
        // 将其他的默认收货地址改成非默认
        if(vo.getIsMain() == 1){
            LambdaQueryWrapper<ShippingAddress> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ShippingAddress::getUserId, userId);
            queryWrapper.eq(ShippingAddress::getIsMain, 1);

            List<ShippingAddress> list = shippingAddressMapper.selectList(queryWrapper);

            for (ShippingAddress address : list) {
                address.setIsMain(0);
                shippingAddressMapper.updateById(address);
            }
        }
        // 判断是否第一个，如果是第一个设置默认
        LambdaQueryWrapper<ShippingAddress> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShippingAddress::getUserId, userId);
        Integer integer = shippingAddressMapper.selectCount(queryWrapper);
        if(integer == 0){
            vo.setIsMain(1);
        }


        if(vo.getId() == null || vo.getId() == 0){
            shippingAddressMapper.insert(vo);
        }else {
            shippingAddressMapper.updateById(vo);
        }
    }

    @Override
    public List<ShippingAddress> getAddress() {
        int userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<ShippingAddress> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShippingAddress::getUserId, userId);
        List<ShippingAddress> list = shippingAddressMapper.selectList(queryWrapper);

        ShippingAddress address = null;
        for (ShippingAddress shippingAddress : list) {
            if(shippingAddress.getIsMain() == 1) {
                address = shippingAddress;
                break;
            }
        }
        if(address != null){
            list.remove(address);
            list.add(0, address);
        }

        return list;
    }

    @Override
    public void deleteAddress(int id) {
        int userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<ShippingAddress> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ShippingAddress::getUserId, userId);
        queryWrapper.eq(ShippingAddress::getId, id);
        shippingAddressMapper.delete(queryWrapper);
    }

    @Override
    public ShippingAddress getAddressById(int id) {
        return shippingAddressMapper.selectById(id);
    }

    @Override
    public MiniShop getShopByShopId(int shopId) {
        MiniShop shop = shopService.getById(shopId);

        shop.setCropList(cropRepository.getCropByShopId(shopId));

        boolean star = userStarRepository.isStart(new StarType(shopId, 2));
        if (star) shop.setIsFollow(1);
        else shop.setIsFollow(0);

        return shop;
    }

    @Transactional
    @Override
    public void followOrUnFollowShop(FollowOrUnFollowShop vo) {
        StarType type = new StarType();
        type.setStarType(2);
        type.setOtherId(vo.getShopId());
        type.setIsStar(vo.getType() == 1);
        userStarRepository.checkStarStatus(type);

        int num = vo.getType() == 1 ? 1 : -1;
        shopService.updateStartNum(vo.getShopId(), num);

    }

    @Override
    public List<MiniShop> startShopList() {
        List<UserStar> stars = userStarRepository.getStarByUserAndType(2);

        return stars.stream().map(star -> {
            MiniShop shop = shopService.getById(star.getOtherId());
            shop.setStartTime(star.getCreateTime());
            return shop;
        }).collect(Collectors.toList());
    }


}




